#
# Copyright (C) Since 2018 ~ 2025, Inc. All Rights Reserved
#
# @Time    : 2025/1/8-下午9:05
# @Author  : Timmy
# @Email   : tangping@cloudstream-tech.com
# @File    : main_window.py
# @Software: lottery
# @Function:
#
import asyncio
import json
from typing import Coroutine

from PyQt5.QtCore import QEvent, Qt
from PyQt5.QtGui import QStandardItem, QStandardItemModel
from PyQt5.QtWidgets import QMainWindow, QHeaderView, QPushButton
from qasync import asyncSlot, QApplication

from frontend.frontend import web_server, stop_server
from models import (
    Activity as ActivityModel
)
from models.types import Activity, Award, People, ShotEvent
from terminal.terminal import Terminal
from ui.wnd_main import Ui_MainWindow
from .create_activity_dialog import CreateActivityDialog
from .web_window import WebWindow


class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)

        self._terminal: Terminal | None = None

        self.label_currentAward.setText('请选择奖项后开始抽奖')

        # 注册 选择框 事件处理函数
        self.comboBox_selectActivity.currentTextChanged.connect(self._on_activity_changed)

        # 注册“菜单按钮” 事件处理函数
        # - 文件菜单
        self.action_addActivity.triggered.connect(self._on_action_add_activity)
        self.action_updateActivity.triggered.connect(self._on_action_update_activity)
        self.action_openFront.triggered.connect(self._on_action_open_front)
        self.action_hideFront.triggered.connect(self._on_action_hide_front)
        self.action_webClean.triggered.connect(self._on_action_web_clean)

        # - 功能菜单
        self.action_function1.triggered.connect(self._on_action_function1)
        self.action_function2.triggered.connect(self._on_action_function2)
        self.action_function3.triggered.connect(self._on_action_function3)

        # 注册“操作按键” 事件处理函数
        self.pushButton_startRoll.clicked.connect(self._on_start_roll)
        self.pushButton_stopRoll.clicked.connect(self._on_stop_roll)
        self.pushButton_startShot.clicked.connect(self._on_btn_start_shot)
        self.pushButton_startShot.installEventFilter(self)
        self.pushButton_startShot.focusOutEvent = self._on_btn_start_shot_focus_out
        self.pushButton_startShot.focusInEvent = self._on_btn_start_shot_focus_in
        self.pushButton_showNameList.clicked.connect(self._on_show_namelist)
        self.pushButton_backMainPage.clicked.connect(self._on_back_main)
        self.pushButton_showAllLucky.clicked.connect(self._on_show_all_lucky)

        # 初始化 奖项 tableview
        model = QStandardItemModel()
        model.setHorizontalHeaderLabels(['名称', '奖品', '数量', '', ''])
        self.tableView_awards.setModel(model)
        header = self.tableView_awards.horizontalHeader()
        header.setSectionResizeMode(QHeaderView.ResizeToContents)
        header.setMaximumHeight(20)

        # 初始化 名单 tableview
        model = QStandardItemModel()
        model.setHorizontalHeaderLabels(['姓名', '部门/身份', 'alpha'])
        self.tableView_people.setModel(model)
        header = self.tableView_people.horizontalHeader()
        header.setSectionResizeMode(QHeaderView.ResizeToContents)
        header.setMaximumHeight(20)

        # 初始化 抽奖结果 tableview
        model = QStandardItemModel()
        model.setHorizontalHeaderLabels(['时间', '奖项', '姓名', ''])
        self.tableView_shotRecord.setModel(model)
        self.tableView_shotRecord.setWordWrap(True)
        header = self.tableView_shotRecord.horizontalHeader()
        header.setSectionResizeMode(QHeaderView.ResizeToContents)
        header.setMaximumHeight(20)

        # 数据初始化
        self.activity: Activity | None = None
        self._web_window: WebWindow | None = None
        self._wait_shot: bool = False

    def eventFilter(self, object, event):
        if (object == self.pushButton_startShot and
                event.type() == QEvent.KeyPress):
            if event.key() == Qt.Key_Return:
                # print('Enter key pressed')
                if self.checkBox_stop.isChecked():
                    return True

                if self.checkBox_continuable.isChecked():
                    loop = asyncio.get_event_loop()
                    if self._wait_shot:
                        loop.create_task(self._on_shot())
                    else:
                        self._wait_shot = True
                        loop.create_task(self.start_roll())
                return True
        return super().eventFilter(object, event)

    @staticmethod
    def _do_future(future: Coroutine):
        loop = asyncio.get_event_loop()
        loop.create_task(future)

    @asyncSlot()
    async def _on_activity_changed(self):
        selected = self.comboBox_selectActivity.currentText()
        if not selected:
            return

        print('activity changed', selected)
        activity = Activity()

        try:
            await activity.load_db_by_name(selected)
        except ValueError as e:
            print(e)
        self._update_by_activity(activity)

    def _update_by_activity(self, activity: Activity):
        # 初始化信息框
        self.textEdit_result.setPlainText('')
        self.label_status.setText("状态栏")
        self.label_totalProbability.setText("0.00%")
        self.label_currentProbability.setText("0.00%")
        self.label_popTotal.setNum(0)
        self.label_hitTotal.setNum(0)
        self.label_awardTotal.setNum(0)

        # 初始化奖项列表
        model = self.tableView_awards.model()
        model.removeRows(0, model.rowCount())
        awards = activity.awards.values()
        # awards = sorted(awards, key=lambda a: a.time)
        for award in awards:
            self._award_list_add_row(award)
        self.label_awardTotal.setNum(activity.get_award_total())
        self.label_popTotal.setNum(activity.get_award_pop_count())

        # 初始化名单
        model = self.tableView_people.model()
        model.removeRows(0, model.rowCount())
        for people in activity.people.values():
            self._people_list_add_row(people)

        self.label_peopleTotal.setNum(activity.get_people_total())
        self.label_hitTotal.setNum(activity.get_hit_people_total())

        # 初始化中奖列表
        model = self.tableView_shotRecord.model()
        model.removeRows(0, model.rowCount())
        for shot in activity.events:
            self._event_list_add_row(shot)

        self.tableView_shotRecord.scrollToBottom()
        self.label_totalProbability.setText("%s%%" % activity.get_rate_total())
        self.activity = activity

    async def init(self):
        await self.init_from_db()
        self._do_future(self._start_web_server())
        self._do_future(self._wait_frontend())

    async def init_from_db(self):
        # 初始化活动选择下拉框
        current_activity = self.comboBox_selectActivity.currentText()
        self.comboBox_selectActivity.clear()

        activities = await ActivityModel.all()
        if not activities:
            return

        activity_obj = None
        for obj in activities:
            if current_activity == obj.name:
                activity_obj = obj
            self.comboBox_selectActivity.addItem(obj.name)

        activity = Activity()
        if not activity_obj:
            activity_obj = activities[0]

        await activity.set_db_object(activity_obj)
        self.comboBox_selectActivity.setCurrentText(activity_obj.name)

    def _award_list_add_row(self, award: Award):
        model = self.tableView_awards.model()
        row_idx = model.rowCount()
        model.setItem(row_idx, 0, QStandardItem(award.name))
        model.setItem(row_idx, 1, QStandardItem(award.content))
        model.setItem(row_idx, 2, QStandardItem(str(award.count)))

        display_btn = QPushButton('中奖名单', self)
        display_btn.setProperty('name', award.name)
        display_btn.clicked.connect(self._award_list_display_award)
        self.tableView_awards.setIndexWidget(model.index(row_idx, 3), display_btn)

        select_btn = QPushButton('选择', self)
        select_btn.setMaximumWidth(40)
        select_btn.setProperty('name', award.name)
        select_btn.clicked.connect(self._award_list_select_award)
        self.tableView_awards.setIndexWidget(model.index(row_idx, 4), select_btn)

        self.tableView_awards.setRowHeight(row_idx, 18)

    def _people_list_add_row(self, people: People):
        model = self.tableView_people.model()
        row_idx = model.rowCount()
        model.setItem(row_idx, 0, QStandardItem(people.name))
        iden = people.dep if people.dep else people.identity
        model.setItem(row_idx, 1, QStandardItem(iden))
        # model.setItem(row_idx, 2, QStandardItem(people.identity))
        model.setItem(row_idx, 2, QStandardItem(str(people.alpha)))

        self.tableView_people.setRowHeight(row_idx, 18)

    def _award_list_select_award(self):
        sender = self.sender()
        name = sender.property('name')
        self.activity.set_current_award(name)
        self.label_currentAward.setText(name)
        self.label_status.setText('请按“开始抽奖”按钮打乱奖池！')

    def _award_list_display_award(self):
        sender = self.sender()
        award_name = sender.property('name')
        award = self.activity.awards.get(award_name)

        self.textEdit_result.clear()
        self.textEdit_result.append(f'{award_name}:')
        self.textEdit_result.append(award.names(with_dep=True))

        loop = asyncio.get_event_loop()
        loop.create_task(self._terminal.show_award_lucky(award, award.lucky))

    def _on_btn_start_shot_focus_out(self, event):
        self.pushButton_startShot.setStyleSheet(
            "QPushButton {"
            "color: white;"
            "background-color: blue;"
            "}")

    def _on_btn_start_shot_focus_in(self, event):
        self.pushButton_startShot.setStyleSheet(
            "QPushButton {"
            "color: white;"
            "background-color: green;"
            "}"
        )

    @asyncSlot()
    async def _on_btn_start_shot(self):
        current_award = self.activity.current_award()
        if not current_award:
            self.label_status.setText("请先选择奖项！")
            return

        num = self.spinBox_eachNumber.value()
        self.textEdit_result.setText("等待‘回车键’按下...")
        self.label_status.setText(f"按‘回车键’将抽出 {num} 位幸运儿！")
        self.label_currentProbability.setText("%s%%" % self.activity.next_rate(num))

        self._wait_shot = True

        await self._terminal.sync_current_award(award=current_award, each=num)
        await self._on_start_roll()

    async def _on_shot(self):
        num = self.spinBox_eachNumber.value()
        replace = self.checkBox_repeatable.isChecked()
        alpha_enabled = self.action_function3.isChecked()
        shot = await self.activity.shot(num, replace, alpha_enabled)
        if not shot.who:
            total = self.activity.get_hit_people_total()
            hit = self.activity.get_people_total()
            if total == hit:
                self.label_status.setText("都已经中过奖了")
                return

        await self._terminal.stop_roll()
        await self._terminal.show_shot(shot.who)

        result = shot.names(with_dep=False)
        # print(result)

        self.textEdit_result.setText(result)
        self.label_status.setText('完成一次抽奖')

        self._event_list_add_row(shot)
        self.tableView_shotRecord.scrollToBottom()
        self.label_hitTotal.setNum(self.activity.get_hit_people_total())
        self.label_popTotal.setNum(self.activity.get_award_pop_count())
        self._wait_shot = False

    def _event_list_add_row(self, shot: ShotEvent):
        model = self.tableView_shotRecord.model()
        row_idx = model.rowCount()
        model.setItem(row_idx, 0, QStandardItem(shot.time.strftime('%H:%M:%S')))
        model.setItem(row_idx, 1, QStandardItem(shot.item.name))
        model.setItem(row_idx, 2, QStandardItem(shot.names()))

        display_btn = QPushButton("重显")
        display_btn.setMaximumWidth(40)
        display_btn.setProperty('eid', shot.eid)
        display_btn.clicked.connect(self._on_record_display)
        self.tableView_shotRecord.setIndexWidget(model.index(row_idx, 3), display_btn)
        self.tableView_shotRecord.setRowHeight(row_idx, 18)

    def _on_record_display(self):
        sender = self.sender()
        eid = sender.property('eid')
        event = self.activity.get_event(eid)
        loop = asyncio.get_event_loop()
        loop.create_task(self._reshow_shot(event))

    async def _reshow_shot(self, shot: ShotEvent):
        await self._terminal.stop_roll()
        await self._terminal.show_shot(shot.who)

        result = shot.names(with_dep=False)
        # print(result)

        self.textEdit_result.setText(result)
        self.label_status.setText('重新显示抽奖结果')

    async def _sync_namelist(self):
        await self._terminal.sync_namelist(list(self.activity.people.values()))

    @asyncSlot()
    async def _on_start_roll(self):
        self.label_status.setText("开始滚动")
        await self._terminal.start_roll()

    async def start_roll(self):
        self.label_status.setText("开始滚动")
        await self._terminal.start_roll()

    @asyncSlot()
    async def _on_stop_roll(self):
        self.label_status.setText("停止滚动")
        await self._terminal.stop_roll()

    @asyncSlot()
    async def _on_show_namelist(self):
        self.label_status.setText("显示全部抽奖人名单")
        await self._terminal.show_namelist()

    @asyncSlot()
    async def _on_show_all_lucky(self):
        self.label_status.setText("显示全部中奖人名单")
        awards = list(self.activity.awards.values())
        sorted(awards, key=lambda x: x.time)
        await self._terminal.show_whole_lucky(awards)

    @asyncSlot()
    async def _on_back_main(self):
        self.label_status.setText("回到主界面")
        await self._terminal.main_page()

    @asyncSlot()
    async def _on_action_add_activity(self):
        dlg = CreateActivityDialog(self)
        dlg.show()
        dlg.finished.connect(self._on_action_activity_finished)

    @asyncSlot()
    async def _on_action_update_activity(self):
        dlg = CreateActivityDialog(self, self.activity)
        dlg.setWindowTitle("修改抽奖活动")
        dlg.show()
        dlg.finished.connect(self._on_action_activity_finished)

    @asyncSlot()
    async def _on_action_activity_finished(self):
        await self.init_from_db()

    @asyncSlot()
    async def _on_action_open_front(self):
        # 获取屏幕数量
        desktop = QApplication.desktop()
        dn = desktop.screenCount()
        print("screen count:", dn)

        if self._web_window:
            if dn > 1:
                self._web_window.showFullScreen()
            else:
                self.show()
            return

        # url = "http://localhost:8000/static/index.html"
        # QDesktopServices.openUrl(QUrl(url))
        x = self.doubleSpinBox_x.value()
        y = self.doubleSpinBox_y.value()
        web = WebWindow(self, x, y)

        # 设置打开到副屏
        if dn > 1:
            assistant = desktop.screenGeometry(screen=1)
            web.setGeometry(assistant)
        web.show()
        self._web_window = web

    @asyncSlot()
    async def _on_action_hide_front(self):
        if self._web_window:
            self._web_window.hide()

    @asyncSlot()
    async def _on_action_web_clean(self):
        self._web_window.clear_page_cache()

    @asyncSlot()
    async def _on_action_function1(self):
        names = ["李智"]
        replaceable = self.checkBox_repeatable.isChecked()
        self.activity.set_must(replaceable, *names)
        who = ','.join(names)
        award = self.activity.current_award()
        award_name = "下一个奖"
        if award:
            award_name = award.name
        self.label_status.setText(f"‘{who}’ 将中 {award_name}")

    @asyncSlot()
    async def _on_action_function2(self):
        names = ["小smart"]
        replaceable = self.checkBox_repeatable.isChecked()
        people = self.activity.set_must(replaceable, *names)
        if people:
            pass

        who = ','.join(names)
        award = self.activity.current_award()
        award_name = "下一个奖"
        if award:
            award_name = award.name
        self.label_status.setText(f"‘{who}’ 将中 {award_name}")

    @asyncSlot()
    async def _on_action_function3(self):
        alpha_enabled = self.action_function3.isChecked()
        print("alpha_enabled:", alpha_enabled)

    @staticmethod
    async def _start_web_server():
        await web_server()

    @staticmethod
    def _stop_web_server():
        stop_server()

    async def _wait_frontend(self):
        self._terminal = Terminal()
        await self._terminal.connect()

        while True:
            message = await self._terminal.receive_message()
            if not message:
                return
            print('message:', message.encode('utf-8'))
            if message == "start":
                await self._sync_namelist()
                continue

            try:
                msg = json.loads(message)
                match msg.get('action'):
                    case 'start':
                        await self._sync_namelist()
                    case _:
                        print('do nothing...')
                        pass
            except Exception as e:
                print(e)

    def __del__(self):
        super().__del__()

        self._stop_web_server()
        loop = asyncio.get_event_loop()
        loop.run_until_complete(self._terminal.close())
